<template>
    <el-upload
        ref="upload"
        class="upload-demo"
        action="#"
        :limit="1"
        :http-request="myUpload"
        :drag="props.drag"
        :on-exceed="handleExceed" 
        :on-change="onChange"
        :on-success="clearAttachments"
        :auto-upload="props.autoUpload"
        :show-file-list="props.showFileList"
        :before-remove="beforeRemove"
        v-model:file-list="fileList"
    >
        <!-- 自动上传 -->
        <template v-if="autoUpload">
            <el-button 
                type="success"
                :loading="buttonLoading"
                :plain="props.plain"
            >
                {{ buttonName }}
            </el-button>
        </template>
        <!-- 手动上传 -->
        <template v-else>
            <template v-if="props.drag">
                <el-icon class="el-icon--upload"><upload-filled /></el-icon>
                <div class="el-upload__text">
                    拖拽文件到这里或 <em>点击上传</em>
                </div>
            </template>
        </template>
        <!-- 不拖拽上传 -->
        <template v-if="!props.autoUpload && !props.drag" #trigger>
            <el-button type="primary">选择文件</el-button>
        </template>
        <el-button  
            v-if="!props.autoUpload && !props.drag" 
            class="ml-3 ms-2" 
            type="success" 
            :loading="buttonLoading"
            @click="$emit(props.methond, fileList)"
        >
            {{ buttonName }}
        </el-button>
        <!-- 上传提示 -->
        <template v-if="props.isTip" #tip>
            <div class="el-upload__tip text-red">{{ props.tip }}</div>
        </template>
    </el-upload>
</template>
<script lang="ts" setup>
    import { ref, watchEffect } from 'vue'
    import { genFileId, ElMessage} from 'element-plus'

    /**
     * 参数类型限制
     */
    interface UploadFileProps {
        autoUpload?: boolean; // 是否自动上传 ==> 非必传（默认为 false）
        drag?: boolean; // 是否支持拖拽上传 ==> 非必传（默认为 false）
        showFileList?: boolean; // 是否显示文件列表 ==> 非必传（默认为 true）
        isTip?: boolean; // 是否显示提示 ==> 非必传（默认为 true）
        tip?:string; // 提示内容 ==> 非必传（默认为 限制单个文件，新文件会覆盖旧文件）
        methond?: string; // 上传方法 ==> 非必传（默认为 ''）
        methondName?: string; // 方法名称 ==> 非必传（默认为 ''）
        acceptedExtensions?: string[]; // 限制的文件内容 ==> 非必传（默认为 []）
        loading?: boolean; // 按钮加载状态 ==> 非必传（默认为 false）
        loadingText?: string // 按钮加载文字 ==> 非必传（默认为 '上传中'）
        plain: boolean // 按钮样式 ==> 非必传（默认为false）
    }
    
    // 接受父组件参数
    const props = withDefaults(defineProps<UploadFileProps>(), {
        autoUpload: false,
        drag: false,
        showFileList: true,
        isTip: true,
        tip: '限制单个文件，新文件会覆盖旧文件',
        methond: '',
        methondName: '',
        acceptedExtensions:[],
        loading: false,
        loadingText: '上传中',
        plain: false
    })

    // 上传组件引用
    const upload = ref()
    // 上传文件列表
    const fileList = ref([]);
    // 上传按钮加载状态
    const buttonLoading = ref(false)
    // 上传按钮名称
    const buttonName = ref('')

    /**
     * 只允许上传一个文件，后一个文件会替换前一个文件
     */
    const handleExceed: UploadProps['onExceed'] = (files) => {
        upload.value!.clearFiles()
        const file = files[0] as UploadRawFile
        file.uid = genFileId()
        upload.value!.handleStart(file)
    }
    /**
    * 文件选择改变时触发
    */
    const onChange = (file, fileListVal) => {
        const extension = file.name.split('.').pop().toLowerCase();
        if (props.acceptedExtensions.length > 0 && !props.acceptedExtensions.includes(extension)) {
            clearAttachments()
            ElMessage.error('不支持该文件类型上传');
            return false;
        }
        fileList.value = fileListVal;
    }
    const beforeRemove =(file, fileListVal) => {
        fileList.value = fileListVal;
    }
    /**
     * 清空附件列表
     */
    const clearAttachments = () => {
        if (upload.value) {
            upload.value.clearFiles(); // 调用实例方法 `clearFiles` 清空附件列表
        }
    };
    /**
     * 自动上传
     */
    const myUpload = () => {
        if(props.autoUpload) {
            emits('myAutoUpload', fileList)
        }
    }
    const emits = defineEmits(['myAutoUpload'])
    // 导出当前组件的fileList，供父组件使用
    defineExpose({
        fileList,
        clearAttachments
    })
    /**
     * 属性监控
     * 1.watch: 既要指明监视的属性，也要指明监视的回调。
     * 2.watchEffect: 不用指明监视哪个属性，监视的回调中用到哪个属性，那就监视哪个属性。
     *
     */
    watchEffect(() => {
        // 按钮名称
        buttonName.value = props.methondName
        // 按钮加载状态
        buttonLoading.value = props.loading
        // 加载中按钮文字变为loadingText的值
        if(props.loading) {
            buttonName.value = props.loadingText
        }
    })
</script>
<style scoped>
</style>